package io.grpc.examples.helloworldtls;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.logging.Logger;

import com.asgard.crypto.CryptoService;
import com.asgard.crypto.ECKey;
import com.asgard.keybox.KeyBox;

import io.grpc.Server;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.examples.helloworldtls.trust.MyTrustManagerFactory;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyServerBuilder;
import io.grpc.stub.StreamObserver;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.PemCertTool;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;

public class NSMHelloWorldServerTls {
	private static final Logger logger = Logger.getLogger(NSMHelloWorldServerTls.class.getName());

	public static void main(String[] args) throws Exception {
		CryptoService.setUseSM(false);
		String keyboxPath = "E:\\develop\\workspace\\eclipse\\asgard\\grpc-tls-test\\src\\main\\resources\\NotSM\\resources\\pbftvp01\\keybox.xml";

//        CryptoService.setUseSM(true);
//        String keyboxPath = "E:\\develop\\tomcat\\apache-tomcat-8.5.54-8203\\resources\\SMTrueSSL\\keybox.xml";

//		final NSMHelloWorldServerTls server = new NSMHelloWorldServerTls("192.168.4.156", 7402, keyboxPath);
		final NSMHelloWorldServerTls server = new NSMHelloWorldServerTls("localhost", 7402, keyboxPath);
		server.start();
		server.blockUntilShutdown();
	}

	private Server server;
	private String host;
	private int port;
	private String keyboxPath;

	public NSMHelloWorldServerTls(String host, int port, String keyboxPath) {
		this.host = host;
		this.port = port;
		this.keyboxPath = keyboxPath;
	}

	@SuppressWarnings("unused")
	private SslContextBuilder getSslContextBuilder() throws Exception {
		File keyBoxFile = new File(keyboxPath);
		KeyBox keyBox = new KeyBox();
		keyBox.loadFromFile(keyBoxFile, "PASSWORD");
		ECKey eckey = keyBox.getKey("ECKey");
		PrivateKey privateKey = eckey.getPrivateKey();
		X509Certificate x509Certificate = keyBox.getCertificate("ENROLL_CERT").getX509Cert();

//		String caPath = HelloWorldNGMServerTls.class.getClassLoader().getResource("openssl-grpc-cert/ca.crt").getPath();
		String certChainFilePath = HelloWorldNGMServerTls.class.getClassLoader().getResource("openssl_cn_local/server.crt").getPath();
		String privateKeyFilePath = HelloWorldNGMServerTls.class.getClassLoader().getResource("openssl_cn_local/server.pem").getPath();
		privateKey = PemCertTool.toPrivateKey(new File(privateKeyFilePath));
		x509Certificate = PemCertTool.toX509Certificates(new File(certChainFilePath))[0];
		
//		SslContextBuilder sslClientContextBuilder = SslContextBuilder.forServer(new File(certChainFilePath), new File(privateKeyFilePath))
		SslContextBuilder sslClientContextBuilder = SslContextBuilder.forServer(privateKey, x509Certificate)
				.clientAuth(ClientAuth.REQUIRE).trustManager(new MyTrustManagerFactory(""));
		return GrpcSslContexts.configure(sslClientContextBuilder, SslProvider.OPENSSL);
	}

	private void start() throws Exception {
		server = NettyServerBuilder.forAddress(new InetSocketAddress(host, port)).addService(new GreeterImpl())
				.sslContext(getSslContextBuilder().build()).build().start();
		logger.info("Server started, listening on " + port);
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				// Use stderr here since the logger may have been reset by its JVM shutdown
				// hook.
				System.err.println("*** shutting down gRPC server since JVM is shutting down");
				NSMHelloWorldServerTls.this.stop();
				System.err.println("*** server shut down");
			}
		});
	}

	private void stop() {
		if (server != null) {
			server.shutdown();
		}
	}

	private void blockUntilShutdown() throws InterruptedException {
		if (server != null) {
			server.awaitTermination();
		}
	}

	static class GreeterImpl extends GreeterGrpc.GreeterImplBase {

		@Override
		public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
			HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
			responseObserver.onNext(reply);
			responseObserver.onCompleted();
		}
	}
}